﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

using LeanEngine.Extensions;
using LeanEngine.Data;
using LeanEngine.Collections;
using LeanEngine.Exception;
using LeanEngine.Business.Security.Data;
using LeanEngine.Business.Security.Entity;

namespace LeanEngine.Business.Security
{
    /// <summary>
    /// Represents a set of basic methods for the security information.
    /// </summary>
    public class BusinessSecurity
    {
        #region Public Static Method Members

        /// <summary>
        /// Validates the user information and creates a token for a successfuly authentication.
        /// </summary>
        /// <exception cref="System.ArgumentNullException"></exception>
        /// <exception cref="LeanEngine.Core.BusinessException"></exception>
        /// <param name="userName">The user name of the user.</param>
        /// <param name="password">The password of the user.</param>
        public static Token LogOn(string userName, string password)
        {
            return LogOn(userName, password, SecurityRepository.Instance);
        }

        /// <summary>
        /// Validates the user information and creates a token for a successfuly authentication.
        /// </summary>
        /// <exception cref="System.ArgumentNullException"></exception>
        /// <exception cref="LeanEngine.Core.BusinessException"></exception>
        /// <param name="userName">The user name of the user.</param>
        /// <param name="password">The password of the user.</param>
        /// <param name="repository">
        ///  The LeanEngine.Business.Security.DataAccess.SecurityRepository instance 
        ///  that has the methods to retrieve the membership information.
        /// </param>
        public static Token LogOn(string userName, string password, ISecurityRepository repository)
        {
            if (userName.IsNullOrEmpty()) throw new ArgumentNullException("userName");
            if (password.IsNullOrEmpty()) throw new ArgumentNullException("password");
            if (repository.IsNull()) throw new ArgumentNullException("repository");

            var appUser = repository.GetMembership(userName, password);

            if (appUser.IsNotNull() &&
                appUser.UserName.IsNotNullOrEmpty())
            {
                return GenerateToken(appUser);
            }
            else
            {
                throw new BusinessException(Resource.ErrorMessages.UserOrPasswordInvalid);
            }
        }

        /// <summary>
        /// Creates a token for the specified membership.
        /// </summary>
        /// <exception cref="System.ArgumentNullException"></exception>
        /// <param name="appUser">The membership information.</param>
        public static Token Authenticate(Membership appUser)
        {
            if (appUser.IsNull()) throw new ArgumentNullException("appUser");

            if (appUser.IsNotNull() &&
                appUser.UserName.IsNotNullOrEmpty())
            {
                return GenerateToken(appUser);
            }
            else
            {
                throw new BusinessException(Resource.ErrorMessages.UserOrPasswordInvalid);
            }
        }

        #endregion

        #region Internal Static Method Members

        internal static int GenerateTokenSign(Membership appUser, Guid tokenId)
        {
            return GenerateTokenSign(appUser.UserName, appUser.Password, tokenId);
        }

        internal static int GenerateTokenSign(string userName, string password, Guid tokenId)
        {
            return (tokenId.ToString() + "{" + userName + "-" + password + "}{internal static int GenerateTokenSign(string userName, string password, Guid tokenId)}").GetHashCode();
        }

        internal static Token GenerateToken(Membership appUser)
        {
            var tokenId = Guid.NewGuid();
            var tokenSign = GenerateTokenSign(appUser, tokenId);

            return new Token(appUser, tokenId, tokenSign);
        }

        #endregion

        #region Public Virtual Method Members

        /// <summary>
        /// Creates a new row in the database whether all data validations are valid.
        /// </summary>
        /// <exception cref="System.ArgumentNullException"></exception>
        /// <exception cref="LeanEngine.Core.BusinessException"></exception>
        /// <param name="membership">The membership to be inserted on the database.</param>
        public virtual Membership CreateMembership(Membership membership)
        {
            if (membership.IsNull()) throw new ArgumentNullException("membership");

            membership.Insert();

            if (membership.AccessExceptionList.IsNotNullOrEmpty())
            {
                membership.AccessExceptionList.Insert();
            }

            return membership;
        }

        #endregion
    }
}
